#include"StringOfSTL.h"

namespace fym
{
    const size_t string::npos = -1;

    void string::reserve(size_t n)
    {
        if (n > _capacity)
        {
            // 异地扩容：建一个空间大小为n的数组
            char* tmp = new char[n + 1];
            
            // 创建成功后交给_str
            // 先复制_str中数据到tmp
            strcpy(tmp, _str);
            // 再将_str指向新创建的tmp空间，指向前别忘了释放旧空间
            delete[] _str;
            _str = tmp;
            // 更新_capacity
            _capacity = n;
        }
    }
    void string::push_back(char c)
    {
        // 先判断是否需要扩容
        if (_size == _capacity)
        {
            reserve(_capacity == 0 ? 4 : 2 * _capacity);
        }
        // 扩容完尾插
        _str[_size] = c;
        _size++;
        // 不要忘了加\0，_size与\0同一个位置
        _str[_size] = '\0';
    }
    void string::append(const char* str)
    {
        // 在_str中尾插一个字符串str，需要插入strlen(str)个字符
        // 先判断是否需要扩容
        size_t len = strlen(str);
        if (_size + len > _capacity)
        {
            // 判断是否能扩2倍
            reserve(_size + len > 2 * _capacity ? _size + len : 2 * _capacity);
        }
        // 扩容完尾插:strcpy能将str中包括\0的字符都拷贝到_str+_size位置及其后
        strcpy(_str + _size, str);
        _size += len;
    }
    string& string::operator+=(char c)
    {
        // +=一个字符，就是push_back尾插一个字符然后返回+=后的对象
        push_back(c);
        return *this;
    }
    string& string::operator+=(const char* str)
    {
        append(str);
        return *this;
    }
    // 在pos位置上插入字符c/字符串str
    string& string::insert(size_t pos, char c)
    {
        assert(pos <= _size);
        if (_size == _capacity)
        {
            reserve(_capacity == 0 ? 4 : 2 * _capacity);
        }

        // end为非负数，当pos为0，while循环无法结束，注意该类型bug
        // 也不能将end该为int，使end可以存储负数，操作符两端操作数类型不匹配时会进行强转，int转为size_t，-1变npos
        /*size_t end = _size;
        while (end >= pos)
        {
            _str[end + 1] = _str[end];
            end--;
        }*/
        size_t end = _size + 1;
        while (end > pos)
        {
            _str[end] = _str[end - 1];
            end--;
        }
        _str[pos] = c;
        _size++;
        return *this;
    }
    string& string::insert(size_t pos, const char* str)
    {
        assert(pos <= _size);
        size_t len = strlen(str);
        if (_size + len > _capacity)
        {
            reserve(_size + len > 2 * _capacity ? _size + len : 2 * _capacity);
        }
        size_t end = _size + len;
        while (end > pos + len - 1)
        {
            _str[end] = _str[end - len];
            end--;
        }
        for (int i = 0; i < len; i++)
        {
            _str[pos + i] = str[i];
        }
        _size += len;
        return *this;
    }
    // 删除pos位置开始的len个字符
    string& string::erase(size_t pos, size_t len)
    {
        assert(pos < _size);

        if (len >= _size - pos)
        {
            _str[pos] = '\0';
            _size = pos;
        }
        else
        {
            for (int i = pos + len; i <= _size; i++)
            {
                _str[i - len] = _str[i];
            }
            _size -= len;
        }
        return *this;
    }
    // 从pos位置开始查找，返回c在string中第一次出现的位置
    size_t string::find(char c, size_t pos) const
    {
        for (int i = pos; i < _size; i++)
        {
            if (_str[i] == c) return i;
        }
        return npos;
    }
    // 返回子串s在string中第一次出现的位置
    size_t string::find(const char* s, size_t pos) const
    {
        assert(pos < _size);
        const char* ptr = strstr(_str + pos, s);
        if (ptr == nullptr) return npos;
        return ptr - _str;
    }
    // 从pos位置开始的len个字符构建一个字符串返回
    string string::substr(size_t pos, size_t len) const
    {
        assert(pos < _size);
        if (len > _size - pos) len = _size - pos;
        string sub;
        sub.reserve(len);
        for (int i = 0; i < len; i++)
        {
            sub += _str[pos + i];
        }
        return sub;
    }
    bool operator<(const string& s1, const string& s2)
    {
        return strcmp(s1.c_str(), s2.c_str()) < 0;
    }
    bool operator<=(const string& s1, const string& s2)
    {
        return s1 < s2 || s1 == s2;
    }
    bool operator>(const string& s1, const string& s2)
    {
        return !(s1 <= s2);
    }
    bool operator>=(const string& s1, const string& s2)
    {
        return !(s1 < s2);
    }
    bool operator==(const string& s1, const string& s2)
    {
        return strcmp(s1.c_str(), s2.c_str()) == 0;
    }
    bool operator!=(const string& s1, const string& s2)
    {
        return !(s1 == s2);
    }
    ostream& operator<<(ostream& out, const string& s)
    {
        // 不需要访问string类的私有成员可以不设置为友元
        for (auto ch : s)
        {
            out << ch;
        }
        return out;
    }
    istream& operator>>(istream& in, string& s)
    {
        s.clear();
        
        // 大量输入的情况下，向s中不断+=字符ch可能导致频繁扩容，若用reserve一次性申请一定空间可能造成空间浪费或者仍需要扩容
        // 此处利用一个buff[N]数组，当buff数组输入满了或者未满但提前输入结束，则将之前输入的所有字符一次性+=到s中，避免频繁扩容
        // 而且相比利用reserve一次性申请足够空间，buff是函数内部的局部对象，函数结束则释放buff空间，不像s中空间长期存在
        const int N = 256;
        char buff[N];
        int i = 0;

        char ch;
        // in >> ch;
        ch = in.get();
        while (ch != ' ' && ch != '\n')
        {
            // 先存入buff数组缓冲
            buff[i++] = ch;
            if (i == N - 1)
            {
                // 当i == N-1时，buff数组满容，最后一位设为\0，然后将数据插入s中
                buff[i] = '\0';
                s += buff;
                i = 0;
            }
            ch = in.get();
        }
        // 如果i > 0说明输入提前结束，buff中还有未插入s的数据
        if (i > 0)
        {
            buff[i] = '\0';
            s += buff;
        }
        return in;
    }
    // 更新string对象的size为n，若n小于等于size，直接更新，大于则判断是否需扩容，size增大多出来的位置用c填充
    void string::resize(size_t n, char c)
    {
        if (n > _size)
        {
            // 如果n大于底层空间大小，则需要重新开辟空间
            if (n > _capacity)
            {
                reserve(n);
            }
            memset(_str + _size, c, n - _size);
        }
        _size = n;
        _str[n] = '\0';
    }
}